using MongoDB.Driver;
using System.Linq.Expressions;

namespace Beauty.Net.MongoDB.Core;

/// <summary>
/// MongoDB服务实现
/// </summary>
public class MongoDBService : IMongoDBService
{
    private readonly IMongoClient _client;
    private readonly MongoDBOptions _options;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="options">MongoDB配置选项</param>
    public MongoDBService(MongoDBOptions options)
    {
        _options = options ?? throw new ArgumentNullException(nameof(options));
        
        // 配置MongoDB客户端设置
        var clientSettings = MongoClientSettings.FromConnectionString(_options.ConnectionString);
        clientSettings.ConnectTimeout = TimeSpan.FromSeconds(_options.ConnectTimeoutSeconds);
        clientSettings.UseTls = _options.UseSsl;
        
        _client = new MongoClient(clientSettings);
    }

    /// <summary>
    /// 获取数据库
    /// </summary>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>MongoDB数据库</returns>
    public IMongoDatabase GetDatabase(string? databaseName = null)
    {
        return _client.GetDatabase(databaseName ?? _options.DatabaseName);
    }

    /// <summary>
    /// 获取集合
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>MongoDB集合</returns>
    public IMongoCollection<T> GetCollection<T>(string? collectionName = null, string? databaseName = null)
    {
        var db = GetDatabase(databaseName);
        return db.GetCollection<T>(collectionName ?? typeof(T).Name);
    }

    /// <summary>
    /// 插入单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="document">文档</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    public void InsertOne<T>(T document, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        collection.InsertOne(document);
    }

    /// <summary>
    /// 异步插入单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="document">文档</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>任务</returns>
    public Task InsertOneAsync<T>(T document, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.InsertOneAsync(document);
    }

    /// <summary>
    /// 插入多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="documents">文档集合</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    public void InsertMany<T>(IEnumerable<T> documents, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        collection.InsertMany(documents);
    }

    /// <summary>
    /// 异步插入多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="documents">文档集合</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>任务</returns>
    public Task InsertManyAsync<T>(IEnumerable<T> documents, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.InsertManyAsync(documents);
    }

    /// <summary>
    /// 查询单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档</returns>
    public T? FindOne<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.Find(filter).FirstOrDefault();
    }

    /// <summary>
    /// 异步查询单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档</returns>
    public Task<T?> FindOneAsync<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.Find(filter).FirstOrDefaultAsync();
    }

    /// <summary>
    /// 查询文档集合
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档集合</returns>
    public List<T> FindMany<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.Find(filter).ToList();
    }

    /// <summary>
    /// 异步查询文档集合
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档集合</returns>
    public Task<List<T>> FindManyAsync<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.Find(filter).ToListAsync();
    }

    /// <summary>
    /// 更新单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="update">更新操作</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>更新结果</returns>
    public UpdateResult UpdateOne<T>(Expression<Func<T, bool>> filter, UpdateDefinition<T> update, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.UpdateOne(filter, update);
    }

    /// <summary>
    /// 异步更新单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="update">更新操作</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>更新结果</returns>
    public Task<UpdateResult> UpdateOneAsync<T>(Expression<Func<T, bool>> filter, UpdateDefinition<T> update, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.UpdateOneAsync(filter, update);
    }

    /// <summary>
    /// 更新多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="update">更新操作</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>更新结果</returns>
    public UpdateResult UpdateMany<T>(Expression<Func<T, bool>> filter, UpdateDefinition<T> update, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.UpdateMany(filter, update);
    }

    /// <summary>
    /// 异步更新多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="update">更新操作</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>更新结果</returns>
    public Task<UpdateResult> UpdateManyAsync<T>(Expression<Func<T, bool>> filter, UpdateDefinition<T> update, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.UpdateManyAsync(filter, update);
    }

    /// <summary>
    /// 删除单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>删除结果</returns>
    public DeleteResult DeleteOne<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.DeleteOne(filter);
    }

    /// <summary>
    /// 异步删除单个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>删除结果</returns>
    public Task<DeleteResult> DeleteOneAsync<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.DeleteOneAsync(filter);
    }

    /// <summary>
    /// 删除多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>删除结果</returns>
    public DeleteResult DeleteMany<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.DeleteMany(filter);
    }

    /// <summary>
    /// 异步删除多个文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>删除结果</returns>
    public Task<DeleteResult> DeleteManyAsync<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.DeleteManyAsync(filter);
    }

    /// <summary>
    /// 替换文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="replacement">替换文档</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>替换结果</returns>
    public ReplaceOneResult ReplaceOne<T>(Expression<Func<T, bool>> filter, T replacement, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.ReplaceOne(filter, replacement, new ReplaceOptions { IsUpsert = true });
    }

    /// <summary>
    /// 异步替换文档
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="replacement">替换文档</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>替换结果</returns>
    public Task<ReplaceOneResult> ReplaceOneAsync<T>(Expression<Func<T, bool>> filter, T replacement, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.ReplaceOneAsync(filter, replacement, new ReplaceOptions { IsUpsert = true });
    }

    /// <summary>
    /// 统计文档数量
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档数量</returns>
    public long Count<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.CountDocuments(filter);
    }

    /// <summary>
    /// 异步统计文档数量
    /// </summary>
    /// <typeparam name="T">文档类型</typeparam>
    /// <param name="filter">过滤条件</param>
    /// <param name="collectionName">集合名称，不指定则使用类型名称</param>
    /// <param name="databaseName">数据库名称，不指定则使用配置中的数据库名称</param>
    /// <returns>文档数量</returns>
    public Task<long> CountAsync<T>(Expression<Func<T, bool>> filter, string? collectionName = null, string? databaseName = null)
    {
        var collection = GetCollection<T>(collectionName, databaseName);
        return collection.CountDocumentsAsync(filter);
    }
}